#ifndef _MY_NIO_SERVER_H_
#define _MY_NIO_SERVER_H_

#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <iostream>
#include <map>
#include <memory>

#include "config.h"
#include "tools.h"
#include "mythreadpool.hpp"


#define MAXBUF 5000000   //最大BUF长度 5MB
#define MAX_EVENT 12000
#define TIME_OUT -1
#define LISTENQ 10000


/*线程池的 类型参数包含（｛任务：【回调，参数】｝）*/
    //  1 参数
    class NIOTaskParam
    {
        public:
            unique_ptr<int>  cfd; /*客户端fd*/
            unique_ptr<char[]>  buf2; /*缓冲区*/
            unique_ptr<HqHttpResHead> res; /*响应*/

            NIOTaskParam(int & fd,  unique_ptr<HqHttpResHead> & r){
                cfd = make_unique<int>(fd);
                res = move(r);
            }
            NIOTaskParam( NIOTaskParam&& t ){
                cfd = move(t.cfd);
                buf2 = move(t.buf2);
                res = move(t.res);
            }
        private:
            NIOTaskParam( ){}
    };

    // 2 回调
    typedef std::function< void (unique_ptr<NIOTaskParam>&  ) > NIOTaskFun;

    // 3 任务 类型
    struct NIOTask
    {
        NIOTaskFun process;    /*回调函数，任务运行时会调用此函数，也是 线程处理函数 */
        unique_ptr<NIOTaskParam>  param; /*回调函数的参数*/

        NIOTask(const NIOTaskFun a,  unique_ptr<NIOTaskParam>& b ){
            process = a;
            param = move(b);
        }
    } ;
    // 线程处理函数，必须符合 HTask_Func (在mythreadpool.hpp中)类型
    void do_task_for_send_func( unique_ptr<NIOTaskParam>& param );
/*end 线程池的 类型参数包含（｛任务：【回调，参数】｝）*/


class NIOServer{
private:
    struct epoll_event        ev, events[MAX_EVENT]; // epoll事件
    struct sockaddr_in        clientaddr, serveraddr; // 地址
    int epfd;     //  epoll句柄
    int listenfd; //监听fd 句柄
    int nfds;    // 事件发生数量
    int conn_fd;
    int i, n ;  // 辅助变量

    char * _buf; // 缓冲区 [MAXBUF]
    int _sock_fd, _offset;  // sock_fd当前处理的fd， offset是读取时候的buf大小
    int port;
    std::string host;

    int handle_accept();
    int handle_error();
    int handle_in();

public:

    // 发送大文件的线程池，固定  个
    unique_ptr<Thread_pool<NIOTask, NIOTaskFun, NIOTaskParam>> sendPool ;

    // 初始化
    NIOServer(std::string host, int port, int thread_pool_num=8);
    ~NIOServer();
    int startNIOServer(); // 开启服务器

    // 对buf和offset进行相应的解包，然后对fd进行相应的操作
    // return： 0正常，-1关闭sock继续，-2错误！
    virtual int unpack_and_pack(char *&buf, int offset, int fd);

    /* NIO，向sock_fd发送所有数据，AllLen数据长度，buf数据数组 */
    static int sendAllData(int sock_fd, int AllLen, char* buf);


};


#endif // _MY_NIO_SERVER_H_
